import uuid
from appCustomers.models.db import engine
from appCustomers.models.models import mCustomer
from sqlalchemy.orm import sessionmaker
from passlib.context import CryptContext
from appCustomers.utils.sec_utils import create_standard_token
from fastapi import HTTPException, status
from appCustomers.utils.log_utils import logger

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
session = sessionmaker(bind=engine)

async def create_customer(newcustomer: mCustomer)->HTTPException:
    logger.info("======================")
    logger.info(newcustomer)
    logger.info("======================")

    customer_dict = newcustomer.dict()

    mysession = session()
    new_customer = mCustomer(**customer_dict)

    customer_to_check = mysession.query(mCustomer).filter(mCustomer.name==newcustomer.name,
                                                          mCustomer.surname==newcustomer.surname,
                                                          mCustomer.phone==newcustomer.phone,
                                                          mCustomer.passport==newcustomer.passport,
                                                          mCustomer.is_active==True
                                                          ).first()

    if customer_to_check is None:
        customer_to_check = mysession.query(mCustomer).filter(mCustomer.phone==newcustomer.phone,
                                                              mCustomer.is_active==True
                                                              ).first()
        if customer_to_check is None:
            customer_to_check = mysession.query(mCustomer).filter(mCustomer.passport==newcustomer.passport,
                                                                  mCustomer.is_active==True
                                                                  ).first()
            if customer_to_check is None:
                logger.info("start to create new customer")
                pool_size = engine.pool.checkedout()
                logger.info(f"Current pool size usage: {pool_size}")

                new_customer.id = uuid.uuid4()
                new_customer.pwd = pwd_context.hash(newcustomer.pwd)

                mysession.add(new_customer)
                mysession.commit()

                logger.info("done")
                pool_size = engine.pool.checkedout()
                logger.info(f"Current pool size usage: {pool_size}")
                data={"sub": newcustomer.email, "phone": newcustomer.phone, "custid": str(new_customer.id) }
                token= create_standard_token(indata=data)
                return {"id":new_customer.id, "name": newcustomer.name, "token": token}
            else:
                logger.error(f"Passport number is already in use: {customer_to_check.passport} for customer {customer_to_check.id}")
                raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Passport already exists")
        else:
            logger.error(f"Phone number is already in use: {customer_to_check.phone} for customer {customer_to_check.id}")
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Phone number already exists")
    else:
        logger.error(f"Customer with this credentials already exists: {customer_to_check.id}")
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Customer already exists")

async def update_customer(updcustomer: mCustomer)->HTTPException:
    mysession = session()
    logger.info("=========")
    logger.info(updcustomer)
    logger.info("=========")

    customer_to_check = mysession.query(mCustomer).filter(mCustomer.phone==updcustomer.phone,
                                                          mCustomer.id!=updcustomer.id,
                                                          mCustomer.is_active==True
                                                          ).first()
    if customer_to_check is not None:
        logger.error(f"Phone number is already in use: {customer_to_check.phone} for customer {customer_to_check.id}")
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Phone number already exists")
    else:
        customer_to_check = mysession.query(mCustomer).filter(mCustomer.passport==updcustomer.passport,
                                                          mCustomer.id!=updcustomer.id,
                                                          mCustomer.is_active==True
                                                          ).first()
        if customer_to_check is not None:
            logger.error(f"Passport number is already in use: {customer_to_check.passport} for customer {customer_to_check.id}")
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Passport already exists")
        else:
            customer_to_upd = mysession.query(mCustomer).filter(mCustomer.id==updcustomer.id,
                                                      mCustomer.is_active==True
                                                      ).first()
            if customer_to_upd is not None:
                if pwd_context.verify(updcustomer.pwd, customer_to_upd.pwd):

                    customer_to_upd.name     = updcustomer.name
                    customer_to_upd.surname  = updcustomer.surname
                    customer_to_upd.email    = updcustomer.email
                    customer_to_upd.passport = updcustomer.passport
                    customer_to_upd.phone    = updcustomer.phone
                    mysession.commit()
                    logger.info("done cust update, new name ")
                    pool_size = engine.pool.checkedout()
                    logger.info(f"Current pool size usage: {pool_size}")
                else:
                    logger.error("password is incorrect")
                    raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Password is incorrect")
            else:
                logger.error("no such customer for update")
                raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No such customer")

    pool_size = engine.pool.checkedout()
    logger.info(f"Current pool size usage: {pool_size}")
    return {"name": updcustomer.name, "is_active": True}

async def delete_customer(delcustomer: mCustomer) -> HTTPException:
    mysession = session()
    customer_to_del = mysession.query(mCustomer).filter(mCustomer.id==delcustomer.id,
                                                      mCustomer.is_active == True
                                                      ).first()
    if customer_to_del is not None:
        if pwd_context.verify(delcustomer.pwd, customer_to_del.pwd):
            customer_to_del.is_active = False
            mysession.commit()
            logger.info("done customer was deleted")
            pool_size = engine.pool.checkedout()
            logger.info(f"Current pool size usage: {pool_size}")
        else:
            logger.error("password is incorrect")
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Password is incorrect")
    else:
        logger.error("no such customer for deletion")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No such customer")

    pool_size = engine.pool.checkedout()
    logger.info(f"Current pool size usage: {pool_size}")
    return {"id": delcustomer.id, "is_active": False}

async def sign_in_customer(logcustomer: mCustomer) -> HTTPException:
    mysession = session()
    data = {"sub": "user@example.com"}
    access_granted = False
    customer_to_chk = mysession.query(mCustomer).filter(mCustomer.phone==logcustomer.phone,
                                                        mCustomer.is_active == True
                                                        ).first()
    if customer_to_chk is not None:
        if pwd_context.verify(logcustomer.pwd, customer_to_chk.pwd):
            data={"sub": customer_to_chk.email, "phone": customer_to_chk.phone, "custid": str(customer_to_chk.id)}
            logger.info(f"login success for phone {logcustomer.phone}")
            pool_size = engine.pool.checkedout()
            logger.info(f"Current pool size usage: {pool_size}")
            access_granted = True
        else:
            logger.error("password is incorrect")
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Password is incorrect")
    else:
        logger.error("no such customer")
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No such customer")

    pool_size = engine.pool.checkedout()
    logger.info(f"Current pool size usage: {pool_size}")

    if access_granted:
      return create_standard_token(indata=data)
    else:
      return {"detail":"Phone number does not exists"}

async def do_cust_check(chkcustomer: mCustomer) -> HTTPException:
    logger.info(chkcustomer)
    mysession = session()

    customer_to_chk = mysession.query(mCustomer).filter(mCustomer.id==chkcustomer.id,
                                                        mCustomer.is_active == True
                                                        ).first()
    if customer_to_chk is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Customer is not valid")
    else:
        return {'status': 'OK'}